﻿using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Inovout.Component;
using Inovout.Data.Repository;
using Inovout.Linq;

namespace Inovout.Data.Domain
{
    [AttributeUsage(AttributeTargets.Property)]
    public class UniqueAttribute : ValidationAttribute
    {
        public string PropertyName { get; set; }
        public UniqueAttribute(string propertyName)
        {
            this.PropertyName = propertyName;
        }
        public string FormatAdditionalFields(string propertyName)
        {
            return "Id," + propertyName;
        }
        protected static IRepository GetRepository(Type modelType)
        {
            Type respositoryType = typeof(IQueryableRepository<>);
            respositoryType = respositoryType.MakeGenericType(modelType);
            return ComponentRegistry.Resolve<IRepository>(respositoryType);
        }
        //public static bool Validate(Type bojectType,object id, string property, string value)
        //{
        //    IRepository repository = GetRepository(bojectType);
        //    QueryCriteria queryCriteria = new QueryCriteria();
        //    queryCriteria.Filters.Add(new FilterCriteria(property, FilterOperation.Eq, value));
        //    DataObject dataObject = repository.Query(queryCriteria).OfType<DataObject>().SingleOrDefault();
        //    return dataObject == null || dataObject.Id == id;
        //}
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value == null)
            {
                //验证唯一性的前提就是必填项，如果不NULL,无法处理。
                return null;
            }
            DataObjectTypeDescriptor dataObjectTypeDescriptor = DataObjectTypeDescriptor.Get(validationContext.ObjectType);
            object id = dataObjectTypeDescriptor.IdentifierProperty.GetValue(validationContext.ObjectInstance);

            IRepository repository = GetRepository(dataObjectTypeDescriptor.DeclaringType);
            QueryCriteria queryCriteria = new QueryCriteria(dataObjectTypeDescriptor.DeclaringType);
            queryCriteria.Filters.Add(new FilterCriteria(validationContext.MemberName ?? PropertyName,
                FilterOperation.Eq, value.ToString()));
            var queryResult = repository.Query(queryCriteria).GetEnumerator();
            if (queryResult.MoveNext() && id != null)
            {
                DataObject dataObject = queryResult.Current as DataObject;
                if (!dataObject.Id.Equals(id))
                {
                    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
                }
            }
            return null;
        }
    }
}
